#include "timer_service.h"
#include "thread_service.h"

#define TIMER_SERVICE_FRAME_INTERVAL 10

cheetah_timer_service TMS;

void cheetah_timer_service_init() {
	cheetah_timer_service* s = &TMS;
	s->cache_list_.head_ = s->cache_list_.tail_ = 0;
	s->cache_list_.lock_ = 0;
	s->list_.head_ = s->list_.tail_ = 0;
}

void cheetah_timer_service_add_timer(cheetah_timer* t) {
	cheetah_timer_service* s = &TMS;
	cheetah_timer_cache_list* list;
	assert(t && !t->next_);
	list = &s->cache_list_;
	ATOM_LOCK(&list->lock_);
	if (list->tail_) {
		list->tail_->next_ = t;
		list->tail_ = t;
	}
	else {
		list->head_ = list->tail_ = t;
	}
	ATOM_UNLOCK(&list->lock_);
}

cheetah_timer* cheetah_timer_service_cache_timer_pop() {
	cheetah_timer_service* s = &TMS;
	cheetah_timer_cache_list* list = &s->cache_list_;
	cheetah_timer* t = 0;
	ATOM_LOCK(&list->lock_);
	if (list->head_) {
		t = list->head_;
		list->head_ = t->next_;
		t->next_ = 0;
		if (!list->head_)
			list->tail_ = 0;
	}
	ATOM_UNLOCK(&list->lock_);
	return t;
}

void cheetah_timer_service_timer_push(cheetah_timer* t) {
	cheetah_timer_service* s = &TMS;
	cheetah_timer_list* list;
	assert(t && !t->next_);
	list = &s->list_;
	if (list->tail_) {
		list->tail_->next_ = t;
		list->tail_ = t;
	}
	else {
		list->tail_ = list->head_ = t;
	}
}

void cheetah_timer_service_check_cache_timer() {
	cheetah_timer* t;
	while (t = cheetah_timer_service_cache_timer_pop()) {
		cheetah_timer_service_timer_push(t);
	}
}

void cheetah_timer_service_check_timer() {
	cheetah_timer_service* s = &TMS;
	cheetah_timer_list* list = &s->list_;
	cheetah_timer* parent = list->head_;
	cheetah_timer* node = 0;
	uint64 now = cheetah_time_ms();

	while (parent) {
		if (parent->release_) {
			list->head_ = parent->next_;
			parent->next_ = 0;
			REF_RELEASE(&parent->ref_);
			parent = list->head_;
		}
		else {
			if (parent->next_hit_time_ <= now) {
				parent->cb_(parent->ctx_, parent->param_);
				parent->next_hit_time_ = now + parent->interval_;
			}
			node = parent->next_;
			break;
		}
	}

	while (node) {
		if (node->release_) {
			parent->next_ = node->next_;
			node->next_ = 0;
			REF_RELEASE(&node->ref_);
			node = parent->next_;
		}
		else {
			if (node->next_hit_time_ <= now) {
				node->cb_(node->ctx_, node->param_);
				node->next_hit_time_ = now + node->interval_;
			}
			parent = node;
			node = node->next_;
		}
	}
}

void cheetah_timer_service_tick(uint32 thread_index) {
	cheetah_timer_service_check_cache_timer();
	cheetah_timer_service_check_timer();
}


void cheetah_timer_service_start() {
	uint32 thread_index = 8;
	cheetah_thread* thread = cheetah_thread_create(thread_index, cheetah_timer_service_tick, TIMER_SERVICE_FRAME_INTERVAL);
	cheetah_thread_start(thread);
}
